/*
 * CollisionModel.cpp
 *
 *  Created on: 09.10.2013
 *      Author: dima
 */

#include "CollisionModel.hpp"
#include "GameObjectModel.hpp"

#include <algorithm>


namespace
{
  Tanks::Model::CollisionModel::CollisionSide
  GetOppositeSide(Tanks::Model::CollisionModel::CollisionSide argSide)
  {
    /*int side = (argSide + 2) % (Tanks::Model::CollisionModel::CollisionEnd);
    return (Tanks::Model::CollisionModel::CollisionSide) side;*/
    if(argSide == Tanks::Model::CollisionModel::CollisionLeft)
      return Tanks::Model::CollisionModel::CollisionRight;

    if(argSide == Tanks::Model::CollisionModel::CollisionUp)
      return Tanks::Model::CollisionModel::CollisionDown;

    if(argSide == Tanks::Model::CollisionModel::CollisionRight)
      return Tanks::Model::CollisionModel::CollisionLeft;

    if(argSide == Tanks::Model::CollisionModel::CollisionDown)
      return Tanks::Model::CollisionModel::CollisionUp;

    return Tanks::Model::CollisionModel::CollisionEnd;
  }
}



Tanks::Model::CollisionModel &
Tanks::
Model::
CollisionModel::
getInstance()
{
  static CollisionModel instance;
  return instance;
}



void
Tanks::
Model::
CollisionModel::
RegisterObject(Tanks::Model::GameObjectModel * argGameObject)
{
  m_registeredObjects.push_back(argGameObject);
}


void
Tanks::
Model::
CollisionModel::
RemoveObject(Tanks::Model::GameObjectModel * argGameObject)
{
  std::vector<GameObjectModel *>::iterator iter;
  iter = std::find(m_registeredObjects.begin(), m_registeredObjects.end(), argGameObject);
  if(iter != m_registeredObjects.end())
  {
    m_registeredObjects.erase(iter);
  }
}



void
Tanks::
Model::
CollisionModel::
CheckCollision(Tanks::Model::GameObjectModel * argGameObject)
{
  std::vector<GameObjectModel *>::const_iterator iter;
  for(iter = m_registeredObjects.begin(); iter != m_registeredObjects.end(); ++ iter)
  {
    // no collision with yourself
    if(*iter == argGameObject) continue;

    CollisionSide side = GetCollisionSide(argGameObject->GetRect(), (*iter)->GetRect());

    if(side != CollisionEnd)
    {
      // inform both colliding objects about collision
      // with opposite sides
      argGameObject->Collision(*iter, side, true);
      (*iter)->Collision(argGameObject, GetOppositeSide(side), false);
    }
  }
}



Tanks::Model::CollisionModel::CollisionSide
Tanks::
Model::
CollisionModel::
GetCollisionSide(SDL_Rect * rect1, SDL_Rect * rect2)
{
  if(rect1->x < rect2->x + rect2->w &&
     rect1->x + rect1->w > rect2->x &&
     rect1->y >= rect2->y &&
     rect1->y <= rect2->y + rect2->h)
  {
    return CollisionUp;
  }

  if(rect1->y < rect2->y + rect2->h &&
     rect1->y + rect1->h > rect2->y &&
     rect1->x >= rect2->x &&
     rect1->x <= rect2->x + rect2->w)
  {
    return CollisionLeft;
  }

  if(rect1->x < rect2->x + rect2->w &&
     rect1->x + rect1->w > rect2->x &&
     rect1->y + rect1->h <= rect2->y + rect2->h &&
     rect1->y + rect1->h >= rect2->y)
  {
    return CollisionDown;
  }

  if(rect1->y < rect2->y + rect2->h &&
     rect1->y + rect1->h > rect2->y &&
     rect1->x + rect1->w >= rect2->x &&
     rect1->x + rect1->w <= rect2->x + rect2->w)
  {
    return CollisionRight;
  }

  return CollisionEnd;
}
